package com.sms.core.service.impl;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.sms.client.exception.SendSmsException;
import com.sms.core.adapter.SendSmsAdapter;
import com.sms.core.request.SendContext;
import com.sms.core.request.SmsRequest;
import com.sms.core.service.ExceptionProcesser;
import com.sms.core.service.SendSmsService;
import com.sms.domain.entity.Application;
import com.sms.domain.entity.ChannelConfig;
import com.sms.domain.entity.SmsHistory;
import com.sms.domain.entity.Template;
import com.sms.domain.service.ApplicationService;
import com.sms.domain.service.ChannelConfigService;
import com.sms.domain.service.SmsHistoryService;
import com.sms.domain.service.TemplateService;

/**
 * @desc 
 * @author WuJiangWu
 * @date 2018年7月21日上午12:43:59
 */
@Service
public class SendSmsServiceImpl implements SendSmsService {
    
    protected Logger logger = LoggerFactory.getLogger(getClass());
    
    @Autowired
    private SmsHistoryService smsHistoryService;
    
    /** 适配器缓存 */
    private Map<String, SendSmsAdapter> mapClass2Adapter = new ConcurrentHashMap<>();
    
    @Autowired
    private ExceptionProcesser exceptionProcesser;
    @Autowired
    private ApplicationService applicationService;
    @Autowired
    private ChannelConfigService channelConfigService;
    @Autowired
    private TemplateService templateService;
    
    /**
     * 发送短信
     * @param context sms
     * @throws SendSmsException x
     */
    @Override
    public void sendSms(SmsRequest request) throws SendSmsException {
        boolean result = false;
        /* 以下是业务检查 */
        String appId = request.getAppId();
        Application app = applicationService.getOne(appId);
        if (app == null) {
        	throw new SendSmsException("对应的应用不存在 appId=" + appId);
        } else if (StringUtils.isBlank(app.getChannelId())) {
        	throw new SendSmsException("没有绑定发送通道 appId=" + appId);
        }
        
        String channelId = app.getChannelId();
        ChannelConfig channelConfig = channelConfigService.getOne(channelId);
        if (channelConfig == null) {
        	throw new SendSmsException("没有获取到应用对应的通道配置，appId=" + appId + ";channelId=" + channelId);
        } else if (StringUtils.isBlank(channelConfig.getSendAdapterClass())) {
        	throw new SendSmsException("发送通道没有配置适配器类参数，channelId=" + channelId);
        }
        
        // 获取适配器类
        SendSmsAdapter adapter = getSendAdapater(channelConfig);
        if (adapter == null) {
        	throw new SendSmsException("发送通道适配器类参数不正确，channelId=" + channelId);
        }
        
        // 参数转换
        SendContext context = new SendContext(request);
        context.setApplication(app);
        context.setChannelConfig(channelConfig);
        
        // 获取模板
        if (StringUtils.isBlank(context.getContent())) {
            String templateCode = request.getTemplateCode();
            Template template = templateService.findByAppAndCode(app.getAppId(), templateCode);
            if (template == null) {
            	throw new SendSmsException("没有找到应用对应的模板，appName=" + app.getName() + "，templateCode=" + templateCode);
            }
            context.setTemplate(template);
        }
        
        try {
            adapter.sendSms(context);
            result = true;
        } catch (SendSmsException ex) {
            exceptionProcesser.addException(ex);
            logger.error("使用网关发送短信失败", ex);
            throw ex;
        } catch (Exception ex) {
            exceptionProcesser.addException(ex);
            logger.error("使用网关发送短信失败", ex);
            throw new RuntimeException("使用网关发送短信失败," + ex.getMessage(), ex);
        } finally {
            // 写入记录
            try {
                SmsHistory sh = SmsHistory.fromSendSmsContext(context);
                sh.setSendResult(result ? 1 : 0);
                smsHistoryService.save(sh);
            } catch (Exception ex) {
                logger.error("保存短信发送记录时异常", ex);
                exceptionProcesser.addException(ex);
            }
        }
    }
    
    /**
     * 将配置转换为发送通道
     * @param channelConfig
     * @return
     * @throws SendSmsException
     */
    private SendSmsAdapter getSendAdapater(ChannelConfig channelConfig) throws SendSmsException {
        String adapterClass = channelConfig.getSendAdapterClass();
        if (StringUtils.isBlank(adapterClass)) {
            return null;
        }
        
        SendSmsAdapter adapter = mapClass2Adapter.get(adapterClass);
        
        if (adapter != null) {
            return adapter;
        }
        
        try {
            Class<?> clazz = Class.forName(adapterClass);
            Object obj = clazz.newInstance();
            if (obj == null || !(obj instanceof SendSmsAdapter)) {
                throw new SendSmsException("绑定的不是有效的适配器，channelConfigId=" + channelConfig.getChannelConfigId());
            }
            adapter = (SendSmsAdapter) obj;
            mapClass2Adapter.put(adapterClass, adapter);
            return adapter;
        } catch (ClassNotFoundException e) {
            throw new SendSmsException("找不到相应的适配器，channelConfigId=" + channelConfig.getChannelConfigId());
        } catch (InstantiationException | IllegalAccessException e) {
            throw new SendSmsException("该适配器类不能够实例化，channelConfigId=" + channelConfig.getChannelConfigId());
        }
    }
    
}
